package com.ailanyin.common.utils;

import cn.hutool.core.lang.UUID;
import com.ailanyin.common.exception.Asserts;
import com.alibaba.fastjson.util.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * 文件工具类
 *
 * @author ailanyin
 * @version 1.0
 * @since 2021/10/25 0025 上午 9:15
 */
public class FileUtil {
    private static final String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";

    private static final String AGENT_MSIE = "MSIE";

    private static final String FILE_URL = "URL";

    private static final String AGENT_FIREFOX = "Firefox";

    private static final String AGENT_CHROME = "Chrome";

    private static final String[] DEFAULT_ALLOWED_EXTENSION = {
            // 图片
            "bmp", "gif", "jpg", "jpeg", "png",
            // word excel powerpoint
            "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
            // 压缩文件
            "rar", "zip", "gz", "bz2",
            // 视频格式
            "mp4", "avi", "rmvb", "blob",
            // pdf
            "pdf"};


    /**
     * @param file 上传的文件
     * @return 文件全路径名称
     */
    public static String upload(MultipartFile file, HttpServletRequest request, String path) {

        // 获取文件后缀名
        String extension = getExtension(file);
        // 判断是否允许上传
        if (!isAllowedExtension(extension)) {
            Asserts.fail("不允许上传该类型文件！");
        }
        // 重命名文件
        String fileName = extractFilename(extension);
        // 新建文件
        File newFile = getAbsoluteFile(fileName, path);
        try {
            file.transferTo(newFile);
            return getUrl(request) + getPathFileName(fileName, path);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 输出指定文件的byte数组
     *
     * @param filePath 文件路径
     * @param os       输出流
     * @return
     */
    public static void writeBytes(String filePath, OutputStream os) throws IOException {
        FileInputStream fis = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                throw new FileNotFoundException(filePath);
            }
            fis = new FileInputStream(file);
            byte[] b = new byte[1024];
            int length;
            while ((length = fis.read(b)) > 0) {
                os.write(b, 0, length);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            IOUtils.close(os);
            IOUtils.close(fis);
        }
    }

    public static String getDownloadPath() {
        return System.getProperty("java.io.tmpdir") + File.separator + "download" + File.separator;
    }

    /**
     * 删除文件
     *
     * @param filePath 文件
     * @return
     */
    public static boolean deleteFile(String filePath) {
        boolean flag = false;
        File file = new File(filePath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    /**
     * 文件名称验证
     *
     * @param filename 文件名称
     * @return true 正常 false 非法
     */
    public static boolean isValidFilename(String filename) {
        return filename.matches(FILENAME_PATTERN);
    }


    /**
     * 下载文件名重新编码
     *
     * @param request  请求对象
     * @param fileName 文件名
     * @return 编码后的文件名
     */
    public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
        final String agent = request.getHeader("USER-AGENT");
        String filename = fileName;
        if (agent.contains(AGENT_MSIE)) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains(AGENT_FIREFOX)) {
            // 火狐浏览器
            filename = new String(fileName.getBytes(), "ISO8859-1");
        } else if (agent.contains(AGENT_CHROME)) {
            // google浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }

    /**
     * 下载文件名重新编码
     *
     * @param response     响应对象
     * @param realFileName 真实文件名
     * @return
     */
    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
        String percentEncodedFileName = percentEncode(realFileName);

        StringBuilder contentDispositionValue = new StringBuilder();
        contentDispositionValue.append("attachment; filename=")
                .append(percentEncodedFileName)
                .append(";")
                .append("filename*=")
                .append("utf-8''")
                .append(percentEncodedFileName);

        response.setHeader("Content-disposition", contentDispositionValue.toString());
    }

    /**
     * 百分号编码工具方法
     *
     * @param s 需要百分号编码的字符串
     * @return 百分号编码后的字符串
     */
    public static String percentEncode(String s) throws UnsupportedEncodingException {
        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
        return encode.replaceAll("\\+", "%20");
    }

    /**
     * 判断文件类型是否是允许上传的类型
     *
     * @param extension 文件类型
     * @return Boolean
     */
    public static boolean isAllowedExtension(String extension) {

        for (String str : DEFAULT_ALLOWED_EXTENSION) {
            if (str.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static String getExtension(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    /**
     * 编码文件名
     */
    public static String extractFilename(String extension) {
        return UUID.fastUUID().toString(true) + "." + extension;
    }

    /**
     * 创建文件
     *
     * @param fileName 文件名
     * @return file
     */
    public static File getAbsoluteFile(String fileName, String path) {
        File desc = new File(path + File.separator + fileName);

        if (!desc.exists()) {
            if (!desc.getParentFile().exists()) {
                desc.getParentFile().mkdirs();
            }
        }
        return desc;
    }

    public static String getPathFileName(String fileName, String path) {
        int dirLastIndex = path.length() + 1;
        String currentDir = StringUtils.substring(path, dirLastIndex);
        return currentDir + "/" + fileName;
    }

    public static String getUrl(HttpServletRequest request) {
        // 解决nginx反向代理后代理前缀丢失的问题
        if (EmptyUtil.isNotEmpty(request.getHeader(FILE_URL))) {
            return request.getHeader(FILE_URL);
        }
        StringBuffer url = request.getRequestURL();
        String contextPath = request.getServletContext().getContextPath();
        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
    }

    public static String getJarPath() {
        try {
            String filePath = FileUtil.class.getProtectionDomain().getCodeSource().getLocation().getFile();
            String jarPath = filePath.split(".jar!")[0];
            return jarPath.substring(0,jarPath.lastIndexOf("/"));
        } catch (Exception e) {
            File desc = new File("/opt/jar");
            if (!desc.exists()) {
                desc.mkdir();
            }
            return "/opt/jar";
        }
    }
}
